#pragma once

const int DEFAULT_FRAME_INTERVAL = 20000; // micro-seconds

// no. of frames that can be skipped in any one animation loop
// i.e the games state is updated but not rendered
const int DEFAULT_MAX_FRAME_SKIPS = 5;

const int MAX_STATS_COUNT = 64;

class AnimationThread
{
protected:
	volatile bool m_bRunning;

	int m_FRAME_INTERVAL; // micro-seconds
	int m_MAX_FRAME_SKIPS; // max allowable frame skips

private:
	HANDLE m_hAnimThread;
	DWORD m_dwThreadId;

	UINT m_uTimerPeriod;

	DWORD m_dwThreadStartTime;		// this is set when the thread is started in Run()
	DWORD m_dwTimeSpentInThread;	// this is set when MAX_STATS_INTERVAL is reached in StoreStats()
	DWORD m_dwPrevStatsTime;		// the last time STATS is calcualted
	DWORD m_dwStatsInterval;		// how long it is from the last STATS calculation
	DWORD m_dwTotalElapsedTime;
	DWORD m_dwFrameCount;
	DWORD m_dwFramesSkipped;
	DWORD m_dwTotalFramesSkipped;

	DWORD m_dwStatsCount;
	double m_dUpsStore[MAX_STATS_COUNT];
	double m_dFpsStore[MAX_STATS_COUNT];
	double m_dAverageFPS;
	double m_dAverageUPS;

	static DWORD CALLBACK ThreadEntry(LPVOID pParam);
	DWORD Run();

	void StoreStats();
	void PrintStats();

protected:
	AnimationThread(int frameInterval=DEFAULT_FRAME_INTERVAL, int maxFrameSkips=DEFAULT_MAX_FRAME_SKIPS);
	virtual ~AnimationThread(void);

	virtual void UpdateGame() = 0;
	virtual void RenderGame() = 0;
	virtual void PaintScreen() = 0;

	void Start();
	void Stop();

	double GetAverageFPS() const;
	double GetAverageUPS() const;
};

inline
double AnimationThread::GetAverageFPS() const
{
	return m_dAverageFPS;
}

inline
double AnimationThread::GetAverageUPS() const
{
	return m_dAverageUPS;
}

